
import os
import socket
import threading
import tkinter as tk
from tkinter import ttk, filedialog, messagebox
from queue import Queue
import qrcode
from PIL import ImageTk, Image

class QRTransfer:
    def __init__(self, parent):
        self.parent = parent
        self.qr_window = None
        self.qr_label = None
        
    def show_qr(self, ip, port):
        if self.qr_window is None:
            self.qr_window = tk.Toplevel(self.parent)
            self.qr_window.title("扫描连接")
            self.qr_window.protocol("WM_DELETE_WINDOW", self.hide_qr)
            
            qr_data = f"http://{ip}:{port}"
            qr = qrcode.QRCode(version=1, box_size=10, border=4)
            qr.add_data(qr_data)
            qr.make(fit=True)
            img = qr.make_image(fill_color="black", back_color="white")
            
            img = img.resize((250, 250), Image.LANCZOS)
            self.qr_img = ImageTk.PhotoImage(img)
            
            frame = tk.Frame(self.qr_window)
            frame.pack(padx=20, pady=20)
            
            self.qr_label = tk.Label(frame, image=self.qr_img)
            self.qr_label.pack()
            
            info_frame = tk.Frame(frame)
            info_frame.pack(pady=10)
            
            tk.Label(info_frame, text=f"IP: {ip}").pack()
            tk.Label(info_frame, text=f"端口: {port}").pack()
            tk.Button(info_frame, text="关闭", command=self.hide_qr).pack(pady=5)
        else:
            self.qr_window.deiconify()
    
    def hide_qr(self):
        if self.qr_window:
            self.qr_window.withdraw()

class FileTransfer:
    def __init__(self):
        self.active = False
        self.socket = None
        
    def send_file(self, file_path, port, progress_callback):
        self.active = True
        try:
            self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.socket.bind(('0.0.0.0', port))
            self.socket.listen(1)
            
            filename = os.path.basename(file_path)
            filesize = os.path.getsize(file_path)
            
            conn, addr = self.socket.accept()
            conn.sendall(f"{filename}|{filesize}".encode())
            
            with open(file_path, 'rb') as f:
                while self.active:
                    data = f.read(4096)
                    if not data: break
                    conn.sendall(data)
                    progress_callback(f.tell(), filesize)
            
            conn.close()
        except Exception as e:
            messagebox.showerror("错误", f"发送失败: {str(e)}")
        finally:
            if self.socket: self.socket.close()
            self.active = False

class TransferGUI:
    def __init__(self):
        self.root = tk.Tk()
        self.root.title("文件快传 v3.0")
        self.transfer = FileTransfer()
        self.qr_transfer = QRTransfer(self.root)
        self.setup_ui()
        
    def setup_ui(self):
        # 主框架
        main_frame = tk.Frame(self.root, padx=20, pady=20)
        main_frame.pack()
        
        # 发送区
        send_frame = tk.LabelFrame(main_frame, text="发送文件", padx=10, pady=10)
        send_frame.grid(row=0, column=0, padx=10, pady=10, sticky="nsew")
        
        tk.Label(send_frame, text="文件路径:").grid(row=0, column=0, sticky="e")
        self.file_entry = tk.Entry(send_frame, width=40)
        self.file_entry.grid(row=0, column=1, padx=5)
        
        tk.Button(send_frame, text="浏览", command=self.browse_file).grid(row=0, column=2)
        
        tk.Label(send_frame, text="端口:").grid(row=1, column=0, sticky="e")
        self.port_entry = tk.Entry(send_frame, width=10)
        self.port_entry.insert(0, "5000")
        self.port_entry.grid(row=1, column=1, sticky="w", padx=5)
        
        self.send_btn = tk.Button(send_frame, text="开始发送", command=self.start_send)
        self.send_btn.grid(row=2, column=1, pady=10)
        
        self.qr_btn = tk.Button(send_frame, text="生成二维码", command=self.generate_qr)
        self.qr_btn.grid(row=2, column=2, padx=5)
        
        self.progress = ttk.Progressbar(send_frame, orient="horizontal", length=300, mode="determinate")
        self.progress.grid(row=3, column=0, columnspan=3, pady=10)
        
        # 接收区
        recv_frame = tk.LabelFrame(main_frame, text="接收文件", padx=10, pady=10)
        recv_frame.grid(row=1, column=0, padx=10, pady=10, sticky="nsew")
        
        tk.Label(recv_frame, text="保存路径:").grid(row=0, column=0, sticky="e")
        self.save_entry = tk.Entry(recv_frame, width=40)
        self.save_entry.grid(row=0, column=1, padx=5)
        
        tk.Button(recv_frame, text="浏览", command=self.browse_save).grid(row=0, column=2)
        
        tk.Label(recv_frame, text="发送方IP:").grid(row=1, column=0, sticky="e")
        self.ip_entry = tk.Entry(recv_frame, width=15)
        self.ip_entry.grid(row=1, column=1, sticky="w", padx=5)
        
        tk.Label(recv_frame, text="端口:").grid(row=2, column=0, sticky="e")
        self.recv_port = tk.Entry(recv_frame, width=10)
        self.recv_port.insert(0, "5000")
        self.recv_port.grid(row=2, column=1, sticky="w", padx=5)
        
        self.recv_btn = tk.Button(recv_frame, text="开始接收", command=self.start_recv)
        self.recv_btn.grid(row=3, column=1, pady=10)
        
        self.recv_progress = ttk.Progressbar(recv_frame, orient="horizontal", length=300, mode="determinate")
        self.recv_progress.grid(row=4, column=0, columnspan=3, pady=10)
        
        # 状态栏
        self.status = tk.Label(main_frame, text="准备就绪", bd=1, relief=tk.SUNKEN, anchor=tk.W)
        self.status.grid(row=2, column=0, sticky="ew", pady=5)
        
    def browse_file(self):
        path = filedialog.askopenfilename()
        if path:
            self.file_entry.delete(0, tk.END)
            self.file_entry.insert(0, path)
            self.progress["maximum"] = os.path.getsize(path)
            
    def browse_save(self):
        path = filedialog.asksaveasfilename()
        if path:
            self.save_entry.delete(0, tk.END)
            self.save_entry.insert(0, path)
            
    def generate_qr(self):
        ip = socket.gethostbyname(socket.gethostname())
        port = int(self.port_entry.get())
        self.qr_transfer.show_qr(ip, port)
        
    def start_send(self):
        file_path = self.file_entry.get()
        if not file_path:
            messagebox.showerror("错误", "请选择要发送的文件")
            return
            
        port = int(self.port_entry.get())
        self.send_btn.config(state="disabled")
        
        threading.Thread(
            target=self.transfer.send_file,
            args=(file_path, port, self.update_progress),
            daemon=True
        ).start()
        
    def start_recv(self):
        save_path = self.save_entry.get()
        if not save_path:
            messagebox.showerror("错误", "请选择保存路径")
            return
            
        ip = self.ip_entry.get()
        port = int(self.recv_port.get())
        self.recv_btn.config(state="disabled")
        
        threading.Thread(
            target=self.receive_file,
            args=(ip, port, save_path),
            daemon=True
        ).start()
        
    def receive_file(self, ip, port, save_path):
        try:
            conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            conn.connect((ip, port))
            
            file_info = conn.recv(1024).decode()
            filename, filesize = file_info.split("|")
            filesize = int(filesize)
            
            save_path = os.path.join(os.path.dirname(save_path), filename)
            
            self.recv_progress["maximum"] = filesize
            received = 0
            
            with open(save_path, 'wb') as f:
                while received < filesize:
                    data = conn.recv(4096)
                    if not data: break
                    f.write(data)
                    received += len(data)
                    self.recv_progress["value"] = received
                    self.status.config(text=f"接收中: {received/1024:.1f}KB/{filesize/1024:.1f}KB")
            
            messagebox.showinfo("完成", f"文件已保存到: {save_path}")
        except Exception as e:
            messagebox.showerror("错误", f"接收失败: {str(e)}")
        finally:
            conn.close()
            self.recv_btn.config(state="normal")
            self.status.config(text="准备就绪")
            
    def update_progress(self, current, total):
        self.progress["value"] = current
        self.status.config(text=f"发送中: {current/1024:.1f}KB/{total/1024:.1f}KB")
        if current >= total:
            self.send_btn.config(state="normal")
            self.status.config(text="发送完成")
            
    def run(self):
        self.root.mainloop()

if __name__ == "__main__":
    app = TransferGUI()
    app.run()
